﻿using OpenCvSharp;
using OpenCvSharp.Dnn;
using OpenCvSharp.Extensions;
using OpenCvSharp.XImgProc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Intrinsics;
using System.Text;
using System.Threading.Tasks;

namespace CutShuFa
{
    public class CVHelper
    {
        // 创建透明背景的MAT
        public static Mat CreateTransparentBackground(int width, int height)
        {
            Mat mat = new Mat(height, width, MatType.CV_8UC4);
            mat.SetTo(new Scalar(0, 0, 0, 0));
            return mat;
        }

        // 替换背景
        public static Mat ReplaceBackground(Mat mat, Mat background)
        {
            Mat result = new Mat();
            Cv2.AddWeighted(mat, 0.5, background, 0.5, 0, result);
            return result;
        }

        // 替换指定颜色为另一种颜色
        public static Mat ReplaceColor(Mat mat, Scalar oldColor, Scalar newColor)
        {
            Mat result = new Mat();
            Cv2.InRange(mat, oldColor, oldColor, result);
            Cv2.BitwiseAnd(mat, mat, result, result);
            Cv2.BitwiseOr(mat, mat, result, result);
            return result;
        }

        /// <summary>
        /// 分离颜色通道，0红， 1绿， 2蓝
        /// </summary>
        /// <param name="mat"></param>
        /// <returns></returns>
        public static Mat[] SplitColor(Mat mat)
        {
            return Cv2.Split(mat);
        }

        /// <summary>
        /// 自定义各通道的比例转灰度, r为红比例，g为绿比例，b为蓝比例
        /// </summary>
        /// <param name="mat"></param>
        /// <param name="r"></param>
        /// <param name="g"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static Mat ToGray(Mat mat, double r = 299, double g = 587, double b = 114)
        {
            double t = r + g + b;
            r /= t;
            g /= t;
            b /= t;
            //生成相同大小的灰度Mat矩阵
            Mat gray = new Mat(mat.Rows, mat.Cols, MatType.CV_8UC1);
            //遍历图像
            for (int i = 0; i < mat.Rows; i++)
            {
                for (int j = 0; j < mat.Cols; j++)
                {
                    //获取像素
                    Vec3b vec = mat.At<Vec3b>(i, j);
                    //计算灰度
                    int _gray = (int)(vec[0] * r + vec[1] * g + vec[2] * b);
                    //赋值
                    gray.Set(i, j, (Byte)_gray);
                }
            }
            return gray;
        }

        /// <summary>
        /// 反色
        /// </summary>
        /// <param name="mat"></param>
        /// <returns></returns>
        public static Mat BitwiseNot(Mat mat)
        {
            Mat bin = new Mat();
            Cv2.BitwiseNot(mat, bin);
            return bin;
        }

        /// <summary>
        /// 二值化，指定阈值
        /// </summary>
        /// <param name="mat"></param>
        /// <param name="threshold"></param>
        /// <returns></returns>
        public static Mat Threshold(Mat mat, int threshold)
        {
            Mat bin = new Mat();
            //THRESH_BINARY：如果像素值大于阈值，则设置为maxval，否则设置为0。
            Cv2.Threshold(mat, bin, threshold, 255, ThresholdTypes.Binary);
            return bin;
        }

        /// <summary>
        /// 二值化，根据直方图计算阈值
        /// </summary>
        /// <param name="mat"></param>
        /// <returns></returns>
        public static Mat Threshold(Mat mat)
        {
            Mat bin = new Mat();
            Cv2.Threshold(mat, bin, 0, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);
            return bin;
        }

        /// <summary>
        /// 膨胀
        /// </summary>
        /// <param name="mat"></param>
        /// <param name="size">核大小，只能为奇数</param>
        /// <returns></returns>
        public static Mat Dilate(Mat mat, int size)
        {
            Mat bin = new Mat();
            Mat k = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(size, size));
            Cv2.Dilate(mat, bin,k);
            return bin;
        }

        /// <summary>
        /// 腐蚀
        /// </summary>
        /// <param name="mat"></param>
        /// <param name="size">核大小，只能为奇数</param>
        /// <returns></returns>
        public static Mat Erode(Mat mat, int size)
        {
            Mat bin = new Mat();
            Mat k = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(size, size));
            Cv2.Erode(mat, bin, k);
            return bin;
        }

        /// <summary>
        /// 形态学处理
        /// </summary>
        /// <param name="mat"></param>
        /// <returns></returns>
        public static Mat MorphologyEx(Mat mat)
        {
            Mat bin = new Mat();
            Cv2.MorphologyEx(mat, bin, MorphTypes.Close, new Mat());
            return bin;
        }

        /// <summary>
        /// 寻找轮廓
        /// </summary>
        public static OpenCvSharp.Point[][] FindContours(Mat mat)
        {
            Cv2.FindContours(mat, out OpenCvSharp.Point[][] contours, out HierarchyIndex[] hierarchy, RetrievalModes.Tree, ContourApproximationModes.ApproxNone);
            return contours;
        }

        // 轮廓坐标变换
        public static void ContoursTransform(OpenCvSharp.Point[][] contours, int x, int y)
        {
            for (int i = 0; i < contours.Length; i++)
            {
                for (int j = 0; j < contours[i].Length; j++)
                {
                    contours[i][j].X -= x;
                    contours[i][j].Y -= y;
                }
            }
        }

        // 轮廓的最大外接矩形


        // 保存灰度图像
        public static void SaveGrayImage(Mat mat, string path)
        {
            Cv2.ImWrite(path, mat);
        }

        // 裁剪四周
        public static Mat Crop(Mat mat, int x, int y, int width, int height)
        {
            //Rect rect = new Rect(x, y, width, height);
            return mat[x, y, width, height];
        }

        /// <summary>
        /// 轮廓描边
        /// </summary>
        /// <param name="mat">填充到</param>
        /// <param name="contours">要填充的轮廓</param>
        /// <param name="color">颜色</param>
        /// <param name="thickness">线条宽度</param>
        public static void DrawContours(Mat mat, OpenCvSharp.Point[][] contours, Scalar color, int thickness = 2)
        {
            Cv2.DrawContours(mat, contours, -1, color, thickness);
        }

        /// <summary>
        /// 填充轮廓
        /// </summary>
        /// <param name="mat"></param>
        /// <param name="contours"></param>
        /// <param name="color"></param>
        public static void FillContours(Mat mat, OpenCvSharp.Point[][] contours, Scalar color)
        {
            Cv2.FillPoly(mat, contours, color);
        }

        /// <summary>
        /// 模糊
        /// </summary>
        /// <param name="mat"></param>
        /// <param name="size">必须为奇数</param>
        /// <returns></returns>
        public static Mat GaussianBlur(Mat mat, OpenCvSharp.Size size)
        {
            Mat mat1 = new Mat();
            Cv2.GaussianBlur(mat, mat1, size, 0);
            return mat1;
        }

        /// <summary>
        /// 画圆
        /// </summary>
        /// <param name="mat"></param>
        /// <param name="center"></param>
        /// <param name="radius"></param>
        /// <param name="color"></param>
        /// <param name="thickness">线宽，或为-1为实心</param>
        public static void Circle(Mat mat, OpenCvSharp.Point center, int radius, Scalar color, int thickness = 2)
        {
            Cv2.Circle(mat, center, radius, color, thickness);
        }
        //画矩形
        public static void Rectangle(Mat mat, OpenCvSharp.Point point1, OpenCvSharp.Point point2, Scalar color, int thickness = 2)
        {
            Cv2.Rectangle(mat, point1, point2, color, thickness);
        }
        //画线
        public static void Line(Mat mat, OpenCvSharp.Point point1, OpenCvSharp.Point point2, Scalar color, int thickness = 2)
        {
            Cv2.Line(mat, point1, point2, color, thickness);
        }
        //绘制文字
        public static void PutText(Mat mat, string text, OpenCvSharp.Point point, HersheyFonts fontFace, double fontScale, Scalar color, int thickness = 2)
        {
            Cv2.PutText(mat, text, point, fontFace, fontScale, color, thickness);
        }
        //Resize
        public static Mat Resize(Mat mat, int width, int height)
        {
            var _mat = new Mat();
            Cv2.Resize(mat, _mat, new OpenCvSharp.Size(width, height));
            return _mat;
        }
        //Resize 按比例缩入
        public static Mat Resize(Mat mat, double scale)
        {
            var _mat = new Mat();
            Cv2.Resize(mat, _mat, new OpenCvSharp.Size(), scale, scale);
            return _mat;
        }
        //crop
        public static Mat Cro2(Mat mat, int x, int y, int width, int height)
        {
            return mat[new OpenCvSharp.Rect(x, y, width, height)];
        }
        //clone
        public static Mat Clone(Mat mat)
        {
            return mat.Clone();
        }
        //opencvsharp4 QRCodeDetector 识别 验证码
        public static string QRCodeDetector(Mat mat)
        {
            QRCodeDetector qrCodeDetector = new QRCodeDetector();
            Point2f[] points;
            string decodedText = qrCodeDetector.DetectAndDecode(mat, out points);

            // Display the result
            if (!string.IsNullOrEmpty(decodedText))
            {
                OpenCvSharp.Point[][] pts = { points.Select(p => new OpenCvSharp.Point(p.X, p.Y)).ToArray() };
                Cv2.Polylines(mat, pts, true, Scalar.Red, 2);
                return decodedText;
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// 添加文字，支持中文
        /// </summary>
        /// <param name="src"></param>
        /// <param name="text"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        Mat PutText(Mat src, string text, int x, int y)
        {
            var dstimg = BitmapConverter.ToBitmap(src);
            using (var g = Graphics.FromImage(dstimg))
            {
                Brush textBrush = new SolidBrush(Color.Green);
                var font = new Font(FontFamily.GenericMonospace, 25, FontStyle.Bold);
                g.DrawString(text, font, textBrush, x, y);
            }
            return BitmapConverter.ToMat((Bitmap)dstimg);
        }
        
    }
}
